package com.aiwu;

import android.os.Environment;
import android.text.TextUtils;

import androidx.annotation.NonNull;

import com.aiwu.library.AiWuFileHelper;
import com.aiwu.library.AiwuSimulator;
import com.aiwu.library.bean.ArchiveBean;
import com.aiwu.utils.FileUtils;
import com.aiwu.utils.ZipUtil;

import org.citra.citra_emu.CitraApplication;
import org.citra.citra_emu.utils.StringUtil;
import org.citra.citra_emu.utils.TimeUtil;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import rx.Observable;
import rx.Subscription;
import rx.schedulers.Schedulers;

/**
 * 备份存档
 */
public class ArchiveBackupManger {
    private static final int maxBackupNum = 25;

    private String mark3DSBakFilePath;
    private List<String> bacFileNameList;
    private long localFileTime = 0;
    private boolean isCheckOutSpecial = false;
    private boolean isSpecial = false;
    private String gameBakFilePath;

    private Subscription mSubscription;
    private OnArchiveBackupCallback mCallback;

    public void setArchiveListener(String romPath, OnArchiveBackupCallback callback) {
        mCallback = callback;
        if (TextUtils.isEmpty(romPath)) {
            romPath = AiwuSimulator.ROM_PATH;
        }
        boolean isNewPath = romPath.contains(AiWuFileHelper.getAiWuSharedDir());
        mark3DSBakFilePath = isNewPath ? AiWuFileHelper.getAiWuSharedDir() : Environment.getExternalStorageDirectory() + "/Android/data/com.aiwu.market";
        mark3DSBakFilePath += "/emuGame/3DS/" + CitraApplication.getRomName() + "/SaveBak/";
        startTimer();
    }

    /**
     * 开始备份计时器
     */
    private void startTimer() {
        stopTimer();
        mSubscription = Observable.interval(0, 5, TimeUnit.SECONDS, Schedulers.io())
                .subscribe(aLong -> checkFileIsModify(),
                        throwable -> {
                            throwable.printStackTrace();
                            //循环
                            startTimer();
                        });
    }

    /**
     * 停止备份计时器
     */
    public void stopTimer() {
        if (mSubscription != null) {
            mSubscription.unsubscribe();
        }
    }

    public List<ArchiveBean> getArchiveList() {
        return getBakDataList();
    }


    public void readArchive(int id) {
        resetBakFile(id);
    }


    public void deleteArchive(int id) {
        deleteBakFile(id);
    }

    private void resetBakFile(int position) {
        String path = mark3DSBakFilePath + getTimeStr(Long.parseLong(bacFileNameList.get(position))) + "/";
        try {
            ZipUtil.unzip(path + getZipName(), getBakFilePath());
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (mCallback != null) {
            mCallback.reloadGame();
        }
    }

    private void deleteBakFile(int position) {
        String path = mark3DSBakFilePath + getTimeStr(Long.parseLong(bacFileNameList.get(position))) + "/";
        FileUtils.deleteDirWithFile(new File(path));
    }

    private List<ArchiveBean> getBakDataList() {
        File f = new File(mark3DSBakFilePath);
        if (!f.exists()) {
            return new ArrayList<>();
        }
        bacFileNameList = FileUtils.getAllFilesName(mark3DSBakFilePath);
        if (bacFileNameList == null) {
            return new ArrayList<>();
        }
        bacFileNameList = getFilesNameByLong(bacFileNameList);
        bacFileNameList.sort((o1, o2) -> Long.valueOf(o2).compareTo(Long.valueOf(o1)));

        List<ArchiveBean> list = new ArrayList<>();
        int i = 0;
        for (String fileName : bacFileNameList) {
            ArchiveBean archiveBean = new ArchiveBean(ArchiveBean.NORMAL, i, "存档" + (i + 1), "备份时间：" + getTimeStr(Long.parseLong(fileName)), "", "");
            list.add(archiveBean);
            i++;
        }
        return list;
    }

    private void checkFileIsModify() {
        if (localFileTime == 0) {
            localFileTime = getBakFileTime("");
            if (localFileTime == 0) {
                return;
            }
            if (!isCheckMarkBakFileExits()) {
                copyBakFile();
                return;
            }
        }
        if (getBakFileTime("") - localFileTime > 5 * 1000) {
            localFileTime = getBakFileTime("");
            checkBakFileCount();
            copyBakFile();
        }
    }

    private String getBakFilePath() {
        if (isCheckOutSpecial && !StringUtil.isEmpty(gameBakFilePath)) {
            return gameBakFilePath;
        }
        String bakFilePath = Util.getBakFilePath(CitraApplication.getRomName());
        File file = new File(bakFilePath);
        if (file.exists()) {
            isCheckOutSpecial = true;
            gameBakFilePath = bakFilePath;
            return bakFilePath;
        }

        String specialBakFilePath = Util.getSpecialBakFilePath(CitraApplication.getRomName());
        File specialFile = new File(specialBakFilePath);
        if (specialFile.exists()) {
            isCheckOutSpecial = true;
            isSpecial = true;
            gameBakFilePath = specialBakFilePath;
            return specialBakFilePath;
        }
        return bakFilePath;
    }


    private boolean isCheckMarkBakFileExits() {
        File f = new File(mark3DSBakFilePath);
        if (!f.exists()) {
            f.mkdirs();
            return false;
        }
        List<String> bakFileList = FileUtils.getAllFilesName(mark3DSBakFilePath);
        return bakFileList != null && bakFileList.size() > 0;
    }

    private void copyBakFile() {
        String newFilePath = mark3DSBakFilePath + getTimeStr(getBakFileTime("")) + "/";
        File newF = new File(newFilePath);
        if (!newF.exists()) {
            newF.mkdirs();
        }
        try {
            ZipUtil.zip(getBakFilePath(), newFilePath + getZipName());
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private long getBakFileTime(String filePath) {
        if (StringUtil.isEmpty(filePath))
            filePath = getBakFilePath();
        File f = new File(filePath);
        if (!f.exists()) {
            return 0;
        }
        long bakFileTime = f.lastModified();
        File a = new File(filePath);
        String[] file = a.list();
        if (file == null) {
            return 0;
        }
        File temp;
        for (String s : file) {
            if (filePath.endsWith(File.separator)) {
                temp = new File(filePath + s);
            } else {
                temp = new File(filePath + File.separator + s);
            }

            if (temp.isFile()) {
                long time = temp.lastModified();
                bakFileTime = Math.max(time, bakFileTime);
            }
            if (temp.isDirectory()) {//如果是子文件夹
                long time = getBakFileTime(temp.getAbsolutePath());
                bakFileTime = Math.max(time, bakFileTime);
            }
        }
        return bakFileTime;
    }


    private void checkBakFileCount() {
        File f = new File(mark3DSBakFilePath);
        if (!f.exists()) {
            f.mkdirs();
            return;
        }
        List<String> bakFileNameList = FileUtils.getAllFilesName(mark3DSBakFilePath);
        if (bakFileNameList == null) {
            return;
        }
        bakFileNameList = getFilesNameByLong(bakFileNameList);
        if (bakFileNameList.size() >= maxBackupNum) {
            bakFileNameList.sort((o1, o2) -> Long.valueOf(o2).compareTo(Long.valueOf(o1)));
            String path = mark3DSBakFilePath + getTimeStr(Long.parseLong(bakFileNameList.get(maxBackupNum - 1))) + "/";
            FileUtils.deleteDirWithFile(new File(path));
        }
    }

    private String getZipName() {
        if (isCheckOutSpecial) {
            if (isSpecial) {
                return "user.zip";
            }
            return "data.zip";
        }
        return "data.zip";
    }

    private List<String> getFilesNameByLong(List<String> times) {
        List<String> longFileName = new ArrayList<>();
        for (String str : times) {
            longFileName.add(getTimeStamp(str) + "");
        }
        return longFileName;
    }


    private long getTimeStamp(String time) {
        return TimeUtil.getTimestampByTime(time, "yyyy-MM-dd HH:mm");
    }

    private String getTimeStr(long timeStamp) {
        return TimeUtil.getFormatTimeByTimeMillis(timeStamp, "yyyy-MM-dd HH:mm");
    }

    private ArchiveBackupManger() {
    }

    /**
     * 单例
     *
     * @return 单例
     */
    public static ArchiveBackupManger getInstance() {
        return Holder.INSTANCE;
    }

    private static class Holder {
        static final ArchiveBackupManger INSTANCE = new ArchiveBackupManger();
    }

    public interface OnArchiveBackupCallback {
        void reloadGame();
    }
}
